
package kuti.grp5;

import java.awt.geom.Point2D;
import static java.lang.Math.*;
import java.util.HashSet;
import java.util.Set;

/**
 * The radar helper contains methods how the radar need to scan the lawn.
 *
 * @author Marc Schorderet <marc.schorderet@edu.hefr.ch>
 * @author Vincenzo Do <vincenzo.do@edu.hefr.ch>
 * 
 */

public class RadarHelper {
    
    /**
     * This method calculate all points from the begin point, with the
     * orientation and the distance specified.
     * 
     * @param begin         Start point of the mesure
     * @param orientation   Orientation of the mesure [0.0 - 2*PI]
     * @param distance      Distance of the mesure (positiv)
     * 
     * @return Returns all points (arround on a int) how the "laser pointer"
     * touch.
     * 
     */
    
    public static Set<Point2D> getPointProfile(Point2D begin, double orientation, double distance){
       
        if(begin == null){
            throw new IllegalArgumentException("The begin point is not defined.");
        }
        
        if(Double.isNaN(begin.getX()) || Double.isNaN(begin.getY())){
            throw new IllegalArgumentException("The begin points values are not a number.");
        }
        
        if(Double.isNaN(orientation)){
            throw new IllegalArgumentException("The orientation is not a numner.");
        }
        
        if(orientation < 0.0 || orientation > 2 * PI){
            throw new IllegalArgumentException("The orientation must be between 0.0 and " + (2*PI)
                    + " current value [" + orientation + "]");
        }
        
        if(Double.isNaN(distance)){
            throw new IllegalArgumentException("The distance is not a not a numner.");
        }
        
        if(distance < 0.0){
            throw new IllegalArgumentException("The distance can't be negativ.");
        }
        
        Set<Point2D> points = new HashSet<Point2D>();
        
        // Calculate the difference of the x and y axis
        double x = cos(orientation) * distance;
        double y = sin(orientation) * distance;
        
        // Calculate the slope
        double slope = y / x;
        
        // Calculate the next point
        Point2D start = doubleToIntPoint(begin, x < 0.0, y < 0.0);
        
        // If the slope is on the x axis
        if(abs(slope) <= 1){
            
            // Get x and y values
            int initX = (int) start.getX();
            int initY = (int) start.getY();
            
            // Calculate the delta on the x axis
            double delta = -(slope * initX) + initY;
            
            // Create the current point and the previous point
            Point2D curPt;
            Point2D prevPt = start;
            
            for(int i = 0; i < abs(x); i++){
                
                // Calculate the current x and y value
                double curX = prevPt.getX() + signum(x);
                double curY = slope * curX + delta;
                
                // Create the current point
                curPt = doubleToIntPoint(new Point2D.Double(curX, curY), x < 0.0, y < 0.0);
                
                // break the loop if the x and y value is not of the lawn area
                if(curPt.getY() < 0.0 || curPt.getY() >= SimulParams.WORLD_HEIGHT ||
                        curPt.getX() < 0.0 || curPt.getX() >= SimulParams.WORLD_WIDTH){
                    break;
                }
                
                points.add(new Point2D.Double(curX-signum(x), curY));
                if(curPt.getY() != prevPt.getY() && curPt.getY() != curY){
                    points.add(new Point2D.Double(curX - signum(x), curY - signum(y)));
                }
                
                // go to next lawn
                prevPt = curPt;
                
            }
            
        }else{
            
            // Calculate the slope on the y axis
            slope = x / y;
            
            // Get the x and y values
            int initX = (int) start.getX();
            int initY = (int) start.getY();
            
            // Calculate the delta on the y axis
            double delta = -(slope * initY) + initX;
            
            // Create the current ponit and the previous point
            Point2D curPt;
            Point2D prevPt = start;
            
            for(int i = 0; i < abs(y); i++){
                
                // Calculate the current X and Y values
                double curY = prevPt.getY() + signum(y);
                double curX = slope * curY + delta;
                
                // Create the current point
                curPt = doubleToIntPoint(new Point2D.Double(curX, curY), x < 0.0 , y < 0.0);
                
                // break the loop if the x and y value is not of the lawn area
                if(curPt.getY() < 0.0 || curPt.getY() >= SimulParams.WORLD_HEIGHT ||
                        curPt.getX() < 0.0 || curPt.getX() >= SimulParams.WORLD_WIDTH){
                    break;
                }
                
                points.add(new Point2D.Double(curX, curY - signum(y)));
                if(curPt.getX() != prevPt.getX() && curPt.getX() != curX){
                    points.add(new Point2D.Double(curX - signum(x), curY - signum(y)));
                }
                
                // go to next lawn
                prevPt = curPt;
                
            }
            
        }
        
        return points;
        
    }
    
    /**
     * This method returns a point2D.Double.
     * 
     * @param pt        The initial point
     * @param onRight   true =  returns the right point of pt
     *                  false = returns the left point of pt
     * @param onTop     true =  returns the top point of pt
     *                  false = returns the bottom point of pt
     * 
     * @return Returns the next point.
     * 
     */
    
    public static Point2D doubleToIntPoint(Point2D pt, boolean onRight, boolean onTop){
        
        if(pt == null){
            throw new IllegalArgumentException("The point is not defined.");
        }
        
        if(Double.isNaN(pt.getX()) || Double.isNaN(pt.getY())){
            throw new IllegalArgumentException("The point values are not a number");
        }
        
        double x = pt.getX();
        double y = pt.getY();
        
        x = (onRight) ? ceil(x) : (int) x;
        y = (onTop)   ? ceil(y) : (int) y;
        
        return new Point2D.Double(x, y);
        
    }
    
}
